package s_utils

import (
	"Infinichat_mixed/entity"
	"Infinichat_mixed/global_utils"
	"context"
	"fmt"
	"github.com/bits-and-blooms/bloom/v3"
	"github.com/jinzhu/gorm"
	"github.com/redis/go-redis/v9"
	"github.com/spf13/viper"
	"github.com/streadway/amqp"
	"log"
	"math/rand"
	"time"
)

var DB *gorm.DB

func InitMYSQL() {
	var err error
	DB, err = gorm.Open("mysql", viper.GetString("mysql.dns"))
	if err != nil {
		panic("failed to connect database")
	}
	DB.LogMode(true)
	createTable()
	//truncateTables()
}

var Ctx = context.Background()
var RedisClient *redis.ClusterClient

func InitRedis() {
	RedisClient = redis.NewClusterClient(&redis.ClusterOptions{
		Addrs: []string{"127.0.0.1:7001", "127.0.0.1:7002", "127.0.0.1:7003", "127.0.0.1:7004", "127.0.0.1:7005", "127.0.0.1:7006"},
	})
	if _, err := RedisClient.Ping(Ctx).Result(); err != nil {
		log.Fatalf("Redis cluster connection error: %v", err)
	}
}

//var RedisPool *redis.Pool
//
//func initPool(address string, maxIdle, maxActive int, IdleTimeout time.Duration) {
//	RedisPool = &redis.Pool{
//		MaxIdle:     maxIdle,
//		MaxActive:   maxActive,
//		IdleTimeout: IdleTimeout,
//		Dial: func() (redis.Conn, error) {
//			return redis.Dial("tcp", address)
//		},
//	}
//}
//
//func InitRedis() {
//	initPool(viper.GetString("redis.dns"), viper.GetInt("redis.maxIdle"),
//		viper.GetInt("redis.maxActive"), time.Duration(viper.GetInt("redis.idleTimeout")))
//}

func InitConfig() {
	viper.SetConfigName("app")
	viper.AddConfigPath("./server/config")
	err := viper.ReadInConfig()
	if err != nil {
		panic(err)
	}
	//fmt.Println("config app:", viper.Get("mysql.dns"))

}

var UserBloomFilter *bloom.BloomFilter

func InitUserBloomFilter() {
	var users []entity.User
	if err := DB.Select("id").Find(&users).Error; err != nil {
		fmt.Println("InitUserBloomFilter fail:", err)
		return
	}
	n := uint(len(users))
	UserBloomFilter = bloom.NewWithEstimates(n, 0.001)
	for _, user := range users {
		UserBloomFilter.Add([]byte(fmt.Sprint(user.ID)))
	}
	return
}

// 初始化 RabbitMQ 连接
var MQ *amqp.Connection

func InitRabbitMQ() {
	var err error
	url := viper.GetString("rabbitmq.dns")
	MQ, err = amqp.Dial(url)
	if err != nil {
		log.Fatalf("无法连接到 RabbitMQ: %v", err)
	}
	log.Println("成功连接到 RabbitMQ")
}

func createTable() {
	tables := []interface{}{
		&entity.User{},
		&entity.Friend{},
		&entity.P2PMsg{},
		&entity.P2MMsg{},
		&entity.Group{},
		&entity.GroupMsg{},
		&entity.GroupInvite{},
	}

	for _, table := range tables {
		if !DB.HasTable(table) {
			if err := DB.AutoMigrate(table); err != nil {
				fmt.Printf("Error creating table %T: %v\n", table, err)
			} else {
				fmt.Printf("Table %T created successfully.\n", table)
			}
		} else {
			fmt.Printf("Table %T already exists.\n", table)
			// 如果表已经存在，检查字段变化并进行迁移
			if err := DB.AutoMigrate(table).Error; err != nil {
				fmt.Printf("Error migrating table %T: %v\n", table, err)
			} else {
				fmt.Printf("Table %T migrated successfully.\n", table)
			}
		}
	}
}

func truncateTables() {
	tableNames := []string{
		"user",
		"friend",
		"p2p_msg",
		"p2m_msg",
		"group",
		"group_msg",
		"group_invite",
	}

	for _, name := range tableNames {
		sql := fmt.Sprintf("TRUNCATE TABLE %s;", name)
		if err := DB.Exec(sql).Error; err != nil {
			fmt.Printf("Error truncating table %s: %v\n", name, err)
		} else {
			fmt.Printf("Table %s truncated successfully.\n", name)
		}
	}

	insertMockUsers(50)
}

func insertMockUsers(n int) {
	sexOptions := []uint8{entity.Male, entity.Female}
	salt := fmt.Sprintf("%06d", rand.Int31())
	pwd := global_utils.MakePassword("123456", salt)
	for i := 0; i < n; i++ {
		user := entity.User{
			Account:    fmt.Sprintf("%d", i+1),
			Password:   pwd,
			Salt:       salt,
			Nickname:   fmt.Sprintf("User%d", i+1),
			Sex:        sexOptions[i%2],
			Phone:      fmt.Sprintf("13%09d", rand.Intn(1e9)),
			Email:      fmt.Sprintf("user%d@example.com", i+1),
			LoginTime:  uint64(time.Now().Unix()),
			LogoutTime: uint64(time.Now().Unix() + 1000),
			ClientIp:   "127.0.0.1",
			ClientPort: "8080",
			UserStatus: entity.UserOffline,
		}

		if err := DB.Create(&user).Error; err != nil {
			fmt.Printf("Error inserting user %d: %v\n", i+1, err)
		} else {
			fmt.Printf("User %d inserted.\n", i+1)
		}
	}
}
